﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Ex04.Menus.Interfaces
{
    public class MenuItem
    {
        private string m_DisplayText;
        private string m_BackText;
        private List<MenuItem> m_MenuItemCollection;
        private List<IMenuItemObserver> m_MenuItemObservers;

        public MenuItem(string i_DisplayText)
        {
            m_BackText = "Back";
            m_DisplayText = i_DisplayText;
            m_MenuItemCollection = new List<MenuItem>();
            m_MenuItemObservers = new List<IMenuItemObserver>();
        }

        public MenuItem(string i_DisplayText, IMenuItemObserver i_MenuItemObserver)
            : this(i_DisplayText)
        {
            m_MenuItemObservers.Add(i_MenuItemObserver);
        }

        public MenuItem(string i_DisplayText, string i_BackText)
            : this(i_DisplayText)
        {
            m_BackText = i_BackText;
        }

        public bool HasSubMenu
        {
            get { return m_MenuItemCollection.Count > 0; }
        }

        public string DisplayText
        {
            get { return m_DisplayText; }
        }

        public void RegisterObserver(IMenuItemObserver i_MenuItemObserver)
        {
            m_MenuItemObservers.Add(i_MenuItemObserver);
        }

        public void UnRegisterObserver(IMenuItemObserver i_MenuItemObserver)
        {
            m_MenuItemObservers.Remove(i_MenuItemObserver);
        }

        /// <summary>
        /// Selects the item.
        /// If the item is a leaf item, invokes the action associated with it.
        /// Otherwise, shows it's submenu.
        /// </summary>
        public void Select()
        {
            if (this.HasSubMenu)
            {
                int userChoice;

                do
                {
                    Console.Clear();
                    showTitleAndMenuItems();
                    userChoice = getUserChoice();

                    if (userChoice != 0)
                    {
                        m_MenuItemCollection[userChoice - 1].Select();
                        OnItemChosen();
                    }
                }
                while (userChoice != 0);
            }
            else
            {
                Console.Clear();
                OnItemChosen();
            }
        }

        protected virtual void OnItemChosen()
        {
            foreach (IMenuItemObserver menuItemObserver in m_MenuItemObservers)
            {
                menuItemObserver.ItemChosen(this);
            }
        }

        private void showTitleAndMenuItems()
        {
            string line;
            Console.WriteLine(m_DisplayText);

            for (int i = 0; i < m_MenuItemCollection.Count; i++)
            {
                MenuItem currentMenuItem = m_MenuItemCollection[i];
                line = string.Format("{0}. {1}", (i + 1).ToString(), currentMenuItem.DisplayText);
                Console.WriteLine(line);
            }

            line = string.Format("{0}. {1}{2}", 0, m_BackText, Environment.NewLine);
            Console.WriteLine(line);
        }

        private int getUserChoice()
        {
            int userChoice;
            string messageToUser = string.Format("Please enter your choice and then press Enter. (A number between {0} and {1}.)", 0, m_MenuItemCollection.Count);
            Console.WriteLine(messageToUser);
            string userChoiceString = Console.ReadLine();
            bool parsingSuccess = int.TryParse(userChoiceString, out userChoice);
            if (!parsingSuccess || userChoice < 0 || userChoice > m_MenuItemCollection.Count)
            {
                userChoice = getUserChoice();
            }

            return userChoice;
        }

        /// <summary>
        /// Adds a menu item to the main menu.
        /// </summary>
        /// <param name="i_MenuItem">The menu item to add.</param>
        public void AddMenuItem(MenuItem i_MenuItem)
        {
            m_MenuItemCollection.Add(i_MenuItem);
        }
    }
}